//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package user_notice_api_serv

import (
	"context"

	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/org_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_dao"
	"atomgit.com/openlinksaas/api-server/dao/user_dao"
	"atomgit.com/openlinksaas/proto-gen-go.git/user_notice_api"
	"go.mongodb.org/mongo-driver/mongo"
)

type UserNoticeApiImpl struct {
	user_notice_api.UnimplementedUserNoticeApiServer
}

func (apiImpl *UserNoticeApiImpl) GetStatus(ctx context.Context, req *user_notice_api.GetStatusRequest) (*user_notice_api.GetStatusResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_notice_api.GetStatusResponse{
			Code:   user_notice_api.GetStatusResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	unReadCount, err := user_dao.UserNoticeDao.Count(ctx, sessionItem.UserId, true, false)
	if err != nil {
		return nil, err
	}
	totalCount, err := user_dao.UserNoticeDao.Count(ctx, sessionItem.UserId, false, false)
	if err != nil {
		return nil, err
	}
	return &user_notice_api.GetStatusResponse{
		Code:        user_notice_api.GetStatusResponse_CODE_OK,
		UnReadCount: unReadCount,
		TotalCount:  totalCount,
	}, nil
}

func (apiImpl *UserNoticeApiImpl) ListNotice(ctx context.Context, req *user_notice_api.ListNoticeRequest) (*user_notice_api.ListNoticeResponse, error) {
	emptyList := []*user_notice_api.UserNoticeInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_notice_api.ListNoticeResponse{
			Code:           user_notice_api.ListNoticeResponse_CODE_WRONG_SESSION,
			ErrMsg:         "会话不存在",
			UserNoticeList: emptyList,
		}, nil
	}
	count, err := user_dao.UserNoticeDao.Count(ctx, sessionItem.UserId, req.FilterByHasRead, req.HasRead)
	if err != nil {
		return nil, err
	}
	noticeItemList, err := user_dao.UserNoticeDao.List(ctx, sessionItem.UserId, req.FilterByHasRead, req.HasRead, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}
	noticeList := []*user_notice_api.UserNoticeInfo{}
	for _, noticeItem := range noticeItemList {
		noticeList = append(noticeList, noticeItem.ToUserNoticeInfo())
	}
	err = apiImpl.addOrgName(ctx, noticeList)
	if err != nil {
		return nil, err
	}
	err = apiImpl.addProjectName(ctx, noticeList)
	if err != nil {
		return nil, err
	}
	err = apiImpl.addSendUserName(ctx, noticeList)
	if err != nil {
		return nil, err
	}
	return &user_notice_api.ListNoticeResponse{
		Code:           user_notice_api.ListNoticeResponse_CODE_OK,
		TotalCount:     count,
		UserNoticeList: noticeList,
	}, nil
}

func (apiImpl *UserNoticeApiImpl) addOrgName(ctx context.Context, noticeList []*user_notice_api.UserNoticeInfo) error {
	orgIdList := []string{}
	for _, notice := range noticeList {
		data, ok := notice.NoticeData.(*user_notice_api.UserNoticeInfo_AddToProjectFromOrgData)
		if ok {
			orgIdList = append(orgIdList, data.AddToProjectFromOrgData.OrgId)
		}
	}
	orgItemList, err := org_dao.OrgInfoDao.ListById(ctx, orgIdList)
	if err != nil {
		return err
	}
	orgNameMap := map[string]string{}
	for _, orgItem := range orgItemList {
		orgNameMap[orgItem.OrgId] = orgItem.BasicInfo.OrgName
	}
	for _, notice := range noticeList {
		data, ok := notice.NoticeData.(*user_notice_api.UserNoticeInfo_AddToProjectFromOrgData)
		if ok {
			data.AddToProjectFromOrgData.OrgName = orgNameMap[data.AddToProjectFromOrgData.OrgId]
		}
	}
	return nil
}

func (apiImpl *UserNoticeApiImpl) addProjectName(ctx context.Context, noticeList []*user_notice_api.UserNoticeInfo) error {
	projectIdList := []string{}
	for _, notice := range noticeList {
		data, ok := notice.NoticeData.(*user_notice_api.UserNoticeInfo_AddToProjectFromOrgData)
		if ok {
			projectIdList = append(projectIdList, data.AddToProjectFromOrgData.ProjectId)
		}
	}
	projectItemList, err := project_dao.ProjectInfoDao.ListById(ctx, projectIdList, false, false)
	if err != nil {
		return err
	}
	projectNameMap := map[string]string{}
	for _, projectItem := range projectItemList {
		projectNameMap[projectItem.ProjectId] = projectItem.BasicInfo.ProjectName
	}
	for _, notice := range noticeList {
		data, ok := notice.NoticeData.(*user_notice_api.UserNoticeInfo_AddToProjectFromOrgData)
		if ok {
			data.AddToProjectFromOrgData.ProjectName = projectNameMap[data.AddToProjectFromOrgData.ProjectId]
		}
	}
	return nil
}

func (apiImpl *UserNoticeApiImpl) addSendUserName(ctx context.Context, noticeList []*user_notice_api.UserNoticeInfo) error {
	userIdList := []string{}
	for _, notice := range noticeList {
		if notice.SendUserId != "" {
			userIdList = append(userIdList, notice.SendUserId)
		}
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	for _, notice := range noticeList {
		userItem, ok := userItemMap[notice.SendUserId]
		if ok {
			notice.SendUserDisplayName = userItem.BasicInfo.DisplayName
			notice.SendUserLogoUri = userItem.BasicInfo.LogoUri
		}
	}
	return nil
}

func (apiImpl *UserNoticeApiImpl) GetNotice(ctx context.Context, req *user_notice_api.GetNoticeRequest) (*user_notice_api.GetNoticeResponse, error) {
	emptyInfo := &user_notice_api.UserNoticeInfo{
		NoticeData: &user_notice_api.UserNoticeInfo_AddToProjectFromOrgData{
			AddToProjectFromOrgData: &user_notice_api.AddToProjectFromOrgData{},
		},
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_notice_api.GetNoticeResponse{
			Code:       user_notice_api.GetNoticeResponse_CODE_WRONG_SESSION,
			ErrMsg:     "会话不存在",
			UserNotice: emptyInfo,
		}, nil
	}
	noticeItem, err := user_dao.UserNoticeDao.Get(ctx, sessionItem.UserId, req.NoticeFromId)
	if err != nil {
		return &user_notice_api.GetNoticeResponse{
			Code:       user_notice_api.GetNoticeResponse_CODE_NO_NOTICE,
			ErrMsg:     "通知不存在",
			UserNotice: emptyInfo,
		}, nil
	}
	noticeList := []*user_notice_api.UserNoticeInfo{noticeItem.ToUserNoticeInfo()}
	err = apiImpl.addOrgName(ctx, noticeList)
	if err != nil {
		return nil, err
	}
	err = apiImpl.addProjectName(ctx, noticeList)
	if err != nil {
		return nil, err
	}
	err = apiImpl.addSendUserName(ctx, noticeList)
	if err != nil {
		return nil, err
	}
	return &user_notice_api.GetNoticeResponse{
		Code:       user_notice_api.GetNoticeResponse_CODE_OK,
		UserNotice: noticeList[0],
	}, nil
}

func (apiImpl *UserNoticeApiImpl) RemoveNotice(ctx context.Context, req *user_notice_api.RemoveNoticeRequest) (*user_notice_api.RemoveNoticeResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_notice_api.RemoveNoticeResponse{
			Code:   user_notice_api.RemoveNoticeResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	noticeItem, err := user_dao.UserNoticeDao.Get(ctx, sessionItem.UserId, req.NoticeFromId)
	if err != nil { //记录不存在
		return &user_notice_api.RemoveNoticeResponse{
			Code: user_notice_api.RemoveNoticeResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = user_dao.UserNoticeDao.Remove(sessCtx, sessionItem.UserId, req.NoticeFromId)
		if err != nil {
			return nil, err
		}
		if noticeItem.AddToProjectFromOrgData != nil {
			err = project_dao.AckJoinDao.Remove(sessCtx, noticeItem.AddToProjectFromOrgData.ProjectId, sessionItem.UserId)
			if err != nil {
				return nil, err
			}
		}
		return &user_notice_api.RemoveNoticeResponse{
			Code: user_notice_api.RemoveNoticeResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*user_notice_api.RemoveNoticeResponse), nil
}

func (apiImpl *UserNoticeApiImpl) MarkHasRead(ctx context.Context, req *user_notice_api.MarkHasReadRequest) (*user_notice_api.MarkHasReadResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_notice_api.MarkHasReadResponse{
			Code:   user_notice_api.MarkHasReadResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	exist, err := user_dao.UserNoticeDao.Exist(ctx, sessionItem.UserId, req.NoticeFromId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &user_notice_api.MarkHasReadResponse{
			Code:   user_notice_api.MarkHasReadResponse_CODE_NO_NOTICE,
			ErrMsg: "通知不存在",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = user_dao.UserNoticeDao.SetHasRead(sessCtx, sessionItem.UserId, req.NoticeFromId)
		if err != nil {
			return nil, err
		}
		return &user_notice_api.MarkHasReadResponse{
			Code: user_notice_api.MarkHasReadResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*user_notice_api.MarkHasReadResponse), nil
}
